<template>
  <view
    class="tn-input"
    :class="[inputClass]"
    :style="inputStyle"
    @tap.stop="handleClick"
  >
    <!-- 文本域 -->
    <textarea
      v-if="type === 'textarea'"
      class="tn-input__textarea"
      :value="inputValue"
      :placeholder="placeholder"
      :placeholder-style="placeholderStyle || 'color: #AAAAAA'"
      :disabled="disabled"
      :maxlength="maxlength"
      :fixed="fixed"
      :focus="focus"
      :confirm-type="confirmType"
      :auto-height="autoHeight"
      :selection-start="selectionStart"
      :selection-end="selectionEnd"
      :cursor-spacing="cursorSpacing"
      :show-confirm-bar="showConfirmBar"
      @input="handleInput"
      @focus="handleFocus"
      @blur="handleBlur"
      @confirm="handleConfirm"
    />
    <!-- input输入框 -->
    <input
      v-else
      class="tn-input__input"
      :type="(type === 'password' || type === 'select') ? 'text' : type"
      :value="inputValue"
      :password="type === 'password' && !showPassword"
      :placeholder="placeholder"
      :placeholder-style="placeholderStyle || 'color: #AAAAAA'"
      :disabled="disabled || type === 'select' || customKeyboard"
      :maxlength="maxlength"
      :focus="focus"
      :confirm-type="confirmType"
      :selection-start="selectionStart"
      :selection-end="selectionEnd"
      :cursor-spacing="cursorSpacing"
      :show-confirm-bar="showConfirmBar"
      @input="handleInput"
      @focus="handleFocus"
      @blur="handleBlur"
      @confirm="handleConfirm"
    />

    <!-- 右边icon -->
    <view class="tn-input__icon">
      <!-- 清除按钮 -->
      <view
        v-if="clearable && inputValue.length > 0 && isFocus"
        class="tn-input__icon__wrap tn-input__icon--clear"
        @tap.stop="handleClear"
      >
        <tn-icon icon="close"/>
      </view>
      <!-- 显示/隐藏密码 -->
      <view
        v-else-if="type === 'password' && passwordIcon"
        class="tn-input__icon__wrap tn-input__icon--password"
        @tap.stop="handleShowHidePassword"
      >
        <tn-icon :icon="showPassword ? 'eye' : 'eye-hide'" />
      </view>
      <!-- 可选箭头 -->
      <view
        v-else-if="type === 'select'"
        class="tn-input__icon__wrap tn-input__icon--select"
        :class="{
          'reverse': selectOpen
        }"
      >
        <tn-icon icon="up-triangle" />
      </view>
      <!-- 自定义图标 -->
      <view
        v-else-if="type === 'text' && rightIcon"
        class="tn-input__icon__wrap"
      >
        <tn-icon :icon="rightIcon" />
      </view>
    </view>
  </view>
</template>

<script lang="ts" setup>
import { inputProps, inputEmits } from '../../../types/tn-input'
import { FormErrorTypeArray, FormItemValidateState } from '../../../types/tn-form'
import { ColorInfo } from '../../../types/tuniao-ui'
import { UPDATE_MODEL_EVENT } from '../../../constants'
import { ref, computed, CSSProperties, watch, nextTick } from 'vue'
import useComponentColor from '../../../libs/hooks/useComponentColor'
import { handleValueWithUnit, trim } from '../../../utils'
import { TextAlignProperty } from 'csstype'
import TnIcon from '../../tn-icon/src/Icon.vue'
import { useFormItem } from '../../tn-form/lib/hooks'
import { showValidateError } from '../../tn-form/lib/utils'

const props = defineProps(inputProps)
const emits = defineEmits(inputEmits)

// formItem
const { form, formItem } = useFormItem()

const { splitColorInfo } = useComponentColor()
// 解析边框颜色
const borderColor = computed<ColorInfo>(() => {
  return splitColorInfo('border', props?.borderColor || '')
})

// input样式
const inputStyle = computed<CSSProperties>(() => {
  let style: CSSProperties = {}
  if (props?.height) {
    style.minHeight = handleValueWithUnit(props.height)
  } else {
    style.minHeight = props.type === 'textarea' ? '120rpx' : '70rpx'
  }
  style.height = style.minHeight
  if (props?.border && !showErrorBorder.value) {
    if (borderColor.value.type === 'style') style.borderColor = borderColor.value.value
  }
  if (props?.inputAlign) style.textAlign = props.inputAlign as TextAlignProperty
  return Object.assign(style, props?.customStyle || {})
})


// input对应的类
const inputClass = computed<string>(() => {
  let clazz: string[] = []
  if (props?.border) {
    clazz.push('tn-border')
    if (showErrorBorder.value) {
      clazz.push('tn-input--error')
    } else {
      if (borderColor.value.type === 'class') clazz.push(borderColor.value.value)
    }
    
  }
  return clazz.join(' ')
})

// 校验状态
const validateState = computed<FormItemValidateState>(() => formItem?.validateState || '')
const showErrorBorder = ref<boolean>(false)
watch(() => validateState.value, (val) => {
  showErrorBorder.value = showValidateError(
    form?.errorType as FormErrorTypeArray,
    val,
    'border'
  )
})

// 输入框的值
let inputValue = ref<string>('')
// 预览密码
let showPassword = ref<boolean>(false)
// 是否聚焦输入框
let isFocus = ref<boolean>(false)

// 处理输入事件
const handleInput = (e: any) => {
  let value = e.detail.value
  // 判断是否需要去除两端空格
  if (props.trim) value = trim(value, 'both')
  // inputValue.value = value
  emits(UPDATE_MODEL_EVENT, value)
  emits('change', value)
  // 过一个生命周期再进行校验，防止微信小程序端还没有获取到数据
  nextTick(() => {
    if (props.validateEvent) {
      formItem?.validate?.('change').catch((err) => {})
    }
  })
}
watch(() => props.modelValue, (nVal: string, oVal: string | undefined) => {
  inputValue.value = nVal
  // select没有触发input事件
  if (nVal !== oVal && props.type === 'select') {
    handleInput({detail: { value: nVal }})
  }
}, {
  immediate: true
})
// 处理获取焦点事件
const handleFocus = () => {
  isFocus.value = true
  emits('focus')
}
// 处理失去焦点事件
const handleBlur = (e: any) => {
  let value = e.detail.value
  // 防止焦点消失后立马消失的清除按钮, 导致点击失败
  setTimeout(() => {
    isFocus.value = false
  }, 500);
  emits('blur', value)
  // 过一个生命周期再进行校验，防止微信小程序端还没有获取到数据
  nextTick(() => {
    if (props.validateEvent) {
      formItem?.validate?.('blur').catch((err) => {})
    }
  })
}
// 处理点击键盘完成按钮事件
const handleConfirm = (e: any) => {
  emits('confirm', e.detail.value || '')
}
// 处理输入框点击事件
const handleClick = () => {
  if (props.customKeyboard) {
    uni.hideKeyboard()
  }
  emits('click')
}

// 处理清空事件
const handleClear = () => {
  emits(UPDATE_MODEL_EVENT, '')
  emits('change', '')
  nextTick(() => {
    if (props.validateEvent) {
      formItem?.validate?.('change').catch((err) => console.error(err))
    }
  })
}
// 处理显示/隐藏密码
const handleShowHidePassword = () => {
  showPassword.value = !showPassword.value
}
</script>

<script lang="ts">
export default {
  options: {
    // 在微信小程序中将组件节点渲染为虚拟节点，更加接近Vue组件的表现(不会出现shadow节点下再去创建元素)
    virtualHost: true
  }
}
</script>

<style lang="scss" scoped>
@import '../../../theme.scss';

.tn-input {
  position: relative;
  width: 100%;
  height: fit-content;
  display: flex;
  align-content: center;
  justify-content: flex-start;
  line-height: normal;
  font-size: $tn-font-size;

  &--error {
    border-color: map-get(map-get($tn-type-color-map, 'danger'), 'normal');
  }

  &__input, &__textarea {
    flex: 1;
    width: 100%;
    height: 100%;
    font-size: inherit;
    padding: 2rpx 10rpx;
  }
  &__input {
    margin-right: 10rpx;
  }
  
  &__icon {
    line-height: 1;
    font-size: 32rpx;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #AAAAAA;
    height: 100%;
    margin-right: 8rpx;

    &--select {
      font-size: 26rpx;
      transition: transform 0.25s linear;
      &.reverse {
        transform: rotate(180deg);
      }
    }
  }
}
</style>
